#include "Rp23DSLoader.h"
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <io.h>

using namespace Rp2;

//---------------------------------------------------------------------------------------------------
TDSLoader::TDSLoader()
{
	
}
//---------------------------------------------------------------------------------------------------
TDSLoader::~TDSLoader()
{

}
//---------------------------------------------------------------------------------------------------
TriMesh* TDSLoader::Load3DS(std::string& rkFilename)
{
	Attributes kAttr;
	kAttr.SetPositionChannels(3);
	kAttr.SetNormalChannels(3);
	kAttr.SetTCoordChannels(0,2);

	// buffer data
	std::vector<Vector3f> kVB;
	std::vector<int> kIB;
	std::vector<Vector2f> kTC;

	// material info
	std::vector<char*> kMName;
	std::vector<int> kMFaceList;

	FILE* pkFile;
	char acName[128];
	unsigned short usChunkID; //Chunk identifier
	unsigned int uiChunkLength; //Chunk length
	unsigned char ucChar; // Char variable
	unsigned short usEQuantity; // Number of elements in each chunk
	unsigned short usFaceInfo;
	int iIndex; // Index variable

	const char*  acDecorated = System::GetPath(rkFilename.c_str(), System::SM_READ);
	if (!acDecorated)
	{
		System::MsgBoxPrintf(TC("TDSLoader::Load3DS"),
			TC("Can not find : %s"), rkFilename.c_str());
		assert(false);
		return 0;
	}
	fopen_s(&pkFile, acDecorated, "rb");
	if (!pkFile)
	{
		System::MsgBoxPrintf(TC("TDSLoader::Load3DS"),
			TC("Can not open file : %s"), rkFilename.c_str());
		assert(false);
		return 0;
	}
	printf("--------------------------------\n");
	printf("Loading %s\n", rkFilename.c_str());
	printf("--------------------------------\n");
	while (ftell(pkFile) < _filelength(_fileno(pkFile))) //Loop to scan the whole file 
	{
//		getche(); //Insert this command for debug (to wait for keypress for each chuck reading)

		System::Read2le(pkFile, 1, &usChunkID);	 //Read the chunk header
		printf("ChunkID : %x\n" ,usChunkID);
		System::Read4le(pkFile, 1, &uiChunkLength); // Read the chunk length
		printf("ChunkLength : %d\n", uiChunkLength);
		
		switch (usChunkID)
		{
			//----------------- MAIN3DS -----------------
			// Description: Main chunk, contains all the other chunks
			// Chunk ID: 4d4d 
			// Chunk Length: 0 + sub chunks
			//-------------------------------------------
		case 0x4D4D:
			break;

			//----------------- EDIT3DS -----------------
			// Description: 3D Editor chunk, objects layout info 
			// Chunk ID: 3d3d (hex)
			// Chunk Length: 0 + sub chunks
			//-------------------------------------------
		case 0x3D3D:
			break;

			//--------------- EDIT_OBJECT ---------------
			// Description: Object block, info for each object
			// Chunk ID: 4000 (hex)
			// Chunk Length: len(object name) + sub chunks
			//-------------------------------------------
		case 0x4000:
			iIndex = 0;
			do 
			{
				System::Read1(pkFile, 1, &ucChar);
				acName[iIndex] = ucChar;
				iIndex++;
			} while (ucChar != '\0' && iIndex < 200);
			break;

			//--------------- OBJ_TRIMESH ---------------
			// Description: Triangular mesh, contains chunks for 3d mesh info
			// Chunk ID: 4100 (hex)
			// Chunk length: 0 + sub chunks
			//-------------------------------------------		
		case 0x4100:
			break;

			//--------------- TRI_VERTEXL ---------------
			// Description: Vertices list
			// Chunk ID: 4110 (hex)
			// Chunk length: 1 x unsigned short (number of vertices) 
			//             + 3 x float (vertex coordinates) x (number of vertices)
			//             + sub chunks
			//-------------------------------------------
		case 0x4110:
		{
			System::Read2le(pkFile, 1, &usEQuantity);
			int iSaveVQ = kVB.size();
			printf("\nNumber of vertices %d\n", usEQuantity);
			printf("Total number of vertices : %d \n", iSaveVQ + usEQuantity);
			Vector3f kV3; 
			for (int i = 0; i < usEQuantity; i++)
			{
				System::Read4le(pkFile, 1, &kV3.X());
				System::Read4le(pkFile, 1, &kV3.Y());
				System::Read4le(pkFile, 1, &kV3.Z());
				kVB.push_back(kV3);

// 				printf("Vertices list: %f	%f	%f\n", pkVB->Position3(i).X(),
// 					pkVB->Position3(i).Y(), pkVB->Position3(i).Z());
			}
			break;
		}
			//--------------- TRI_FACEL1 ----------------
			// Description: Polygons (faces) list
			// Chunk ID: 4120 (hex)
			// Chunk length: 1 x unsigned short (number of polygons) 
			//             + 3 x unsigned short (polygon points) x (number of polygons)
			//             + sub chunks
			//-------------------------------------------

		case 0x4120:
		{	
			// index buffer
			System::Read2le(pkFile, 1, &usEQuantity);
			int iSaveIQ = kIB.size();
			
			printf("Number of polygons %d\n", usEQuantity);
			printf("Total number of polygons : %d\n", iSaveIQ/3 + usEQuantity);
			unsigned short aiData[3];
			for (int i = 0; i < usEQuantity; i++)
			{
				System::Read2le(pkFile, 1, &aiData[2]);
				System::Read2le(pkFile, 1, &aiData[1]);
				System::Read2le(pkFile, 1, &aiData[0]);
				System::Read2le(pkFile, 1, &usFaceInfo);
				// add the offset
				kIB.push_back(iSaveIQ + aiData[2]);
				kIB.push_back(iSaveIQ + aiData[1]);
				kIB.push_back(iSaveIQ + aiData[0]);

// 				printf("%d : Index data: (%d, %d, %d)\n",iSaveIQ/3 + i,aiData[2],
// 					aiData[1], aiData[0]);

/*				printf("Face flags: %x\n", usFaceInfo);*/
			}
			break;
		}

			//------------- Material information ------------
			// Description: faces list
			// Chunk ID: 4130 (hex)
			// Chunk length: len(object name) + 
			// 1 x unsigned short (number of polygons use this material) + 
			// (number of polygons) * unsigned short (polygons' faces list)
			//-------------------------------------------
		case 0x4130:
		{
			// read object name
			iIndex = 0;
			do 
			{
				System::Read1(pkFile, 1, &ucChar);
				acName[iIndex] = ucChar;
				iIndex++;
			} while (ucChar != '\0' && iIndex < 128);
/*			System::MsgBoxPrintf("","name %s", acName);*/
			kMName.push_back(acName);

			unsigned short usFaceIndex;
			System::Read2le(pkFile, 1, &usEQuantity);
/*			System::MsgBoxPrintf("","quantity %d", (int)usEQuantity);*/
			for (int i = 0; i < usEQuantity; i++)
			{
				System::Read2le(pkFile, 1, &usFaceIndex);
/*				System::MsgBoxPrintf("","face index %d", (int)usFaceIndex);*/
				kMFaceList.push_back((int)usFaceIndex);
			}

			// skip this chunk now
/*			fseek(pkFile, uiChunkLength-6, SEEK_CUR); */
			break;
		}

			//------------- TRI_MAPPINGCOORS ------------
			// Description: Vertices list
			// Chunk ID: 4140 (hex)
			// Chunk length: 1 x unsigned short (number of mapping points) 
			//             + 2 x float (mapping coordinates) x (number of mapping points)
			//             + sub chunks
			//-------------------------------------------
		case 0x4140:
		{
			// texture coordinates
			System::Read2le(pkFile, 1, &usEQuantity);
			Vector2f kV2;
			for (int i = 0; i < usEQuantity; i++)
			{
				System::Read4le(pkFile, 1, &kV2.X());
				System::Read4le(pkFile, 1, &kV2.Y());
				kTC.push_back(kV2);
// 				printf("Texture coordinates: (%f, %f)\n", pkVB->TCoord2(0,i).X(),
// 					pkVB->TCoord2(0,i).Y());
			}
			break;
		}

		case 0xA300:
		{
			// read object name
			iIndex = 0;
			do 
			{
				System::Read1(pkFile, 1, &ucChar);
				acName[iIndex] = ucChar;
				iIndex++;
			} while (ucChar != '\0' && iIndex < 128);
			System::MsgBoxPrintf(TC(""),TC("%s"), acName);

		}

			//----------- Skip unknown chunks ------------
			//We need to skip all the chunks that currently we don't use
			//We use the chunk length information to set the file pointer
			//to the same level next chunk
			//-------------------------------------------
		default:
			// '6' is 3ds chunk header size, unsigned short + int.
			fseek(pkFile, uiChunkLength-6, SEEK_CUR); 
		}
	}
	fclose(pkFile);
	printf("--------------------------------\n");
	printf("End loading %s\n", rkFilename.c_str());
	printf("--------------------------------\n");

	// Copy buffer data
	std::vector<Vector3f>::iterator kVIter;
	std::vector<Vector2f>::iterator kTIter;
	std::vector<int>::iterator kIIter;
	int i;
	VertexBuffer* pkVB = new VertexBuffer(kAttr, kVB.size());
	for (i = 0, kVIter = kVB.begin(), kTIter = kTC.begin();
		i < (int)kVB.size(); i++)
	{
		pkVB->Position3(i) = *kVIter;
		pkVB->TCoord2(0, i) = *kTIter;
		kVIter++;
		kTIter++;
	}
	
	IndexBuffer* pkIB = new IndexBuffer(kIB.size());
	for (i = 0, kIIter = kIB.begin(); i < (int)kIB.size(); i++)
	{
		(*pkIB)[i] = (int)*kIIter;
		kIIter++;
	}

	// material info


	// for debug
// 	pkVB->PrintToFile("Vbuffer.txt");
// 	pkIB->PrintToFile("Ibuffer.txt");
	ModelInfo kInfo;

	ModelMesh* pkMoMesh = new ModelMesh(pkVB,pkIB, kInfo);
	return pkMoMesh;
}
//---------------------------------------------------------------------------------------------------
